using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Farm.Map;

namespace Farm.AStar
{
    public class AStar : Singleton<AStar>
    {
        private GridNodes gridNodes;
        private Node startNode;
        private Node targetNode;
        private int gridWidth;
        private int gridHeight;
        private int originX;
        private int originY;

        private List<Node> openNodeList;        //当前选中Node周围的8个点
        private HashSet<Node> closeNodeList;    //所有被选中的点
        private bool pathFound;//是否找到路径


        
        /// <summary>
        /// 构建路径
        /// </summary>
        /// <param name="sceneName"></param>
        /// <param name="startPos"></param>
        /// <param name="endPos"></param>
        /// <param name="npcMovementStack"></param>
        public void BuiltPath(string sceneName, Vector2Int startPos, Vector2Int endPos,Stack<MovementStep> npcMovementStack)
        {
            pathFound = false;
            if (GenerateGridNodes(sceneName,startPos,endPos))
            {
                //查找最短路径
                if (FindShortestPath())
                {
                    UpdatePathOnMovementStepStack(sceneName,npcMovementStack);
                }
            }
        }
        
        
        /// <summary>
        /// 构建网格节点信息
        /// </summary>
        /// <param name="场景名"></param>
        /// <param name="起始位置，可以直接把当前物体的位置传入"></param>
        /// <param name="结束位置，同上"></param>
        /// <returns></returns>
        private bool GenerateGridNodes(string sceneName,Vector2Int startPos,Vector2Int endPos)
        {
            if (GridMapManager.Instance.GetGridDimensions(sceneName,out Vector2Int gridDimensions,out Vector2Int gridOrigin))
            {
                gridNodes = new(gridDimensions.x, gridDimensions.y);
                gridWidth = gridDimensions.x;
                gridHeight = gridDimensions.y;
                originX = gridOrigin.x;
                originY = gridOrigin.y;

                openNodeList = new List<Node>();
                closeNodeList = new HashSet<Node>();
                
            }
            else
            {
                return false; 
            }

            startNode = gridNodes.GetGridNode(startPos.x - originX, startPos.y - originY);
            targetNode = gridNodes.GetGridNode(endPos.x - originX, endPos.y - originY);

            for (int x = 0; x < gridWidth; x++)
            {
                for (int y = 0; y < gridHeight; y++)
                {
                    Vector3Int tilePos = new Vector3Int(x + originX, y + originY, 0);
                    var key = tilePos.x + "x" + tilePos.y + "y" + sceneName;

                    TileDetails tile = GridMapManager.Instance.GetTileDetails(key);
                    if (tile != null)
                    {
                        Node node = gridNodes.GetGridNode(x, y);

                        if (tile.isNPCObstacle)
                        {
                            node.isObstacle = true;
                        }
                    }
                }
            }
            return true;
        }


        private bool FindShortestPath()
        {
            //添加起点
            openNodeList.Add(startNode);
            while (openNodeList.Count>0)
            {
                openNodeList.Sort(); 
                Node closeNode = openNodeList[0];
                openNodeList.RemoveAt(0);
                closeNodeList.Add(closeNode);
                if (closeNode==targetNode)
                {
                    pathFound = true;
                    break;
                }
                
                //计算周围八个Node补充到OpenList
                EvaluateNeighbourNodes(closeNode);
            }

            return pathFound;
        }

        private void EvaluateNeighbourNodes(Node currentNode)
        {
            Vector2Int currentNodePos = currentNode.gridPosition;
            Node validNeighbourNode;

            for (int x = -1; x <=1; x++)
            {
                for (int y = -1; y <=1; y++)
                {
                    if (x==0&&y==0)
                        continue;
                    validNeighbourNode = GetValidBeighbourNode(currentNodePos.x+x, currentNodePos.y+y);

                    if (validNeighbourNode!=null)
                    {
                        if (!openNodeList.Contains(validNeighbourNode))
                        {
                            validNeighbourNode.gCost = currentNode.gCost + GetDistance(currentNode, validNeighbourNode);
                            validNeighbourNode.hCost = GetDistance(currentNode, validNeighbourNode);

                            validNeighbourNode.parentNode = currentNode;
                            openNodeList.Add(validNeighbourNode);
                        }
                    }
                }
            }
        }


        /// <summary>
        /// 寻找可用的Node点，不是阻挡物，且不是边界，且没有选择
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private Node GetValidBeighbourNode(int x, int y)
        {
            if (x >= gridWidth || y >= gridHeight || x < 0 || y < 0)
                return null;

            Node neighbourNode = gridNodes.GetGridNode(x, y);

            if (neighbourNode.isObstacle || closeNodeList.Contains(neighbourNode))
                return null;
            else
                return neighbourNode;
        }
        
        
        /// <summary>
        /// 判断两点的距离值，直线每格是10，斜线每格是14
        /// </summary>
        /// <param name="nodeA"></param>
        /// <param name="nodeB"></param>
        /// <returns></returns>
        private int GetDistance(Node nodeA, Node nodeB)
        {
            int xDistance = Mathf.Abs(nodeA.gridPosition.x - nodeB.gridPosition.x);
            int yDistance = Mathf.Abs(nodeA.gridPosition.y - nodeB.gridPosition.y);

            if (xDistance > yDistance)
            {
                return 14 * yDistance + 10 * (xDistance - yDistance);
            }
            return 14 * xDistance + 10 * (yDistance - xDistance);
        }

        
        /// <summary>
        /// 更新每一步的坐标和场景名字
        /// </summary>
        /// <param name="sceneName"></param>
        /// <param name="npcMovementSteps"></param>
        private void UpdatePathOnMovementStepStack(string sceneName,Stack<MovementStep> npcMovementSteps)
        {
            Node nextNode = targetNode;

            while (nextNode!=null)
            {
                MovementStep newStep = new MovementStep();
                newStep.sceneName = sceneName;
                newStep.gridCoordinate =
                    new Vector2Int(nextNode.gridPosition.x + originX, nextNode.gridPosition.y + originY);
                
                npcMovementSteps.Push(newStep);
                nextNode = nextNode.parentNode;
            }
        }
    }
}

